Prepare the Workspace
knitr::opts_chunk$set(warning=FALSE, message=FALSE, error = FALSE) # rmd options
rm(list = ls()); invisible(gc()) # cleaning
Control Block
# f, f, 0.25 looks nice.
allowmigrants <- F # OPTIONS: T, F
allowsympatry <- F # OPTIONS: T, F
minoverperc <- 0 # remove pairs that do not have thermal overlap (anagenesis)
costvar <- "ele"
Packages & Prefs
options(scipen = 999) # turn off scientific notation
'%notin%' <- Negate('%in%')
require(ggplot2) # load packages
require(GGally)
require(viridis)
require(caper)
library(dplyr)
library(stringr)
library(maps)
library(ape)
library(EnvStats)
library(forecast)
require(nlme)
require(geodist)
require(letsR)
require(spdep)
require(spatialreg)
require(rnaturalearth)
require(rnaturalearthdata)
require(rgeos)
require(sf)
require(rgdal)
require(raster)
world <- ne_coastline(scale = "medium", returnclass = "sf")
vlog <- function(x){
log( x + abs(min( x , na.rm = T)) + 1)
}
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
exclusion <- read.csv(file = "exclusion_nonsimpatric_nonmigrant.csv")
exclusion$realm1red[is.na(exclusion$realm1red)] <- "NA" # NA is north america not R's NA value. fix.
exclusion$realm2green[is.na(exclusion$realm2green)] <- "NA"
Load Main Data
# main dataframe ---------------------------------
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Process_Cluster_Outputs/Data")
load(file = "Pair_Barrier_Data_FEB2021.rdata")
mydata <- mypairdata; rm(mypairdata)
rownames(mydata) <- mydata$Species.1
mydatahold <- mydata
initial masks
# migration ---
if(allowmigrants == F){
mydata <- mydata[which(mydata$Migration == 1.0),]
}
# patry
if(allowsympatry == F){
mydata <- mydata[which(mydata[,paste0(costvar, "_c0")] > 0 ),] # doesnt matter if you use ele, mat, vart paths here, will be same answer
}
sort
mydata$uniquePairId == exclusion$mydata.uniquePairId
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[31] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[91] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[151] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[211] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[241] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
x <- mydata[which(mydata$Species.1 == "Apteryx_owenii"),]
mydata <- mydata[order(match(mydata$uniquePairId,exclusion$mydata.uniquePairId)), ]
y <- mydata[which(mydata$Species.1 == "Apteryx_owenii"),]
# sum(y!=x, na.rm = T) # checks.
# head(mydata)
mydata$uniquePairId == exclusion$mydata.uniquePairId
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[37] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[73] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[109] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[145] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[181] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[217] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[253] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
rm(x,y)
# # Basic range maps for all pairs (no paths)
# wdPAM <- "/Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data"
# setwd(wdPAM); load("cbPAM.rdata")
# setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Process_Cluster_Outputs/Data")
# pdf("pairmaps2.pdf", width = 19, height = 9.25)
# for (i in 1:nrow(mydata)){
# x <- cbPAM[,c("Longitude(x)","Latitude(y)",mydata$Species.1bl[i])]
# x <- as.data.frame(x[x[,3] == 1,])
# if(ncol(x) == 1) {
# x <- t(x)
# colnames(x) <- c("lon", "lat", "pres")
# x <- as.data.frame(x)
# } else {
# colnames(x) <- c("lon", "lat", "pres")
# }
#
# y <- cbPAM[,c("Longitude(x)","Latitude(y)",mydata$Species.2bl[i])]
# y <- as.data.frame(y[y[,3] == 1,])
# if(ncol(y) == 1) {
# y <- t(y)
# colnames(y) <- c("lon", "lat", "pres")
# y <- as.data.frame(y)
#
# } else {
# colnames(y) <- c("lon", "lat", "pres")
# }
# z <- ggplot(world)+
# geom_sf() +
# geom_point(data = x, aes(y=lat, x=lon), color = "red") +
# geom_point(data = y, aes(y=lat, x=lon), color = "green") +
# theme_bw() +
# ggtitle(i)
# print(z)
# }
# print(i)
# dev.off()
mydata_exclusion <- cbind(mydata, exclusion)
save(mydata_exclusion, file = "mydata_exclusion.rdata")
mydata$realm1 <- exclusion$realm1red
mydata$realm2 <- exclusion$realm2green
mydata$realm <- paste0(mydata$realm1, mydata$realm2)
table(mydata$realm)
AAAA AAIM ATAT ATIM ATPA IMAA IMAT IMIM IMNT NANA NTAA NTNA NTNT OCOC PAAT PANA PAPA
30 1 45 3 1 3 3 27 1 4 1 1 135 2 3 2 6
mydata$realm[mydata$realm == "AAIM"]; mydata$realm[mydata$realm == "IMAA"] <- "AAIM"
[1] "AAIM"
mydata$realm[mydata$realm == "ATIM"]; mydata$realm[mydata$realm == "IMAT"] <- "ATIM"
[1] "ATIM" "ATIM" "ATIM"
mydata$realm[mydata$realm == "ATPA"]; mydata$realm[mydata$realm == "PAAT"] <- "ATPA"
[1] "ATPA"
mydata$realm[mydata$realm == "IMNT"]; mydata$realm[mydata$realm == "NTIM"] <- "IMNT"
[1] "IMNT"
mydata$realm[mydata$realm == "NTAA"]; mydata$realm[mydata$realm == "AANT"] <- "NTAA"
[1] "NTAA"
mydata$realm[mydata$realm == "NTNA"]; mydata$realm[mydata$realm == "NANT"] <- "NTNA"
[1] "NTNA"
mydata$realm[mydata$realm == "PANA"]; mydata$realm[mydata$realm == "NAPA"] <- "PANA"
[1] "PANA" "PANA"
mydata$realm <- as.factor(mydata$realm); mydata$realm <- relevel(mydata$realm, "NTNT")
mydata$landgap <- as.logical(exclusion$island)
mydata$cosmopolitan <- as.logical(exclusion$cosmopolitan)
mydata$new.old <- as.logical(exclusion$new.old)
rm(exclusion, mydata_exclusion)
Impose masks & do calcuations
# filter cosmopolitan and new/old world species (there are relatively few after imposing previous masks.)
mydata <- mydata[which(mydata$cosmopolitan == FALSE & mydata$new.old == FALSE),]
# dependent variable: elevational barrier size ---
mydata$cost <- mydata[, paste0(costvar, "_c25")]
# data filtering -----------------------
# thermal overlap ---
mydata$MAT_overlap <- mydata[,paste0("MAT", "_ov_perc_smrnge")]
mydata <- mydata[mydata$MAT_overlap > minoverperc,]
# update sort order --------------------
mydata$sortorder <- seq(1:nrow(mydata))
# longitude ----------------------------
mydata$lon <- mydata[,paste0("lon_mean_pair_", costvar, "_c25")]
# latitude ----------------------------
mydata$lat <- mydata[,paste0("lat_mean_pair_", costvar, "_c25")]
# temperature breadth -----------------
mydata$tas_breadth <- mydata$tas_range # mean(mean(sp1 annual tas range -- one value per cell), mean(sp2 annual tas range -- one value per cell))
# mean annual temperature --------------
mydata$tas_position <- mydata$tas_mean # mean(mean(sp1 annual tas mean -- one value per cell), mean(sp2 annual tas mean -- one value per cell))
# precipitation breadth ---------------
mydata$pcp_breadth <- mydata$pcp_range # mean(mean(sp1 annual pcp range -- one value per cell), mean(sp2 annual pcp range -- one value per cell))
# precipitation breadth ---------------
mydata$pcp_position <- mydata$pcp_mean # mean(mean(sp1 annual pcp mean -- one value per cell), mean(sp2 annual pcp mean -- one value per cell))
# distance -----------------------------
mydata$distance <- mydata[,paste0("centroid_distance_",costvar,"_c25")]
# mountain mass ------------------------
mtns <- readOGR(dsn="~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/GMBA", layer="GMBA Mountain Inventory_v1.2-World", verbose = FALSE)
wdPAM <- "/Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data"
setwd(wdPAM); load("LonLat_BirdPAM_raster.rdata")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
mtns <- rasterize(mtns, LonLat_BirdPAM_raster)
load phylo and prune
# phylo ------------------------------------------
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/BirdTrees")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/BirdTrees inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
load(file = "BirdTrees.Rdata")
tree <- trees[[1]]; rm(trees) # pick tree (VF GET TREES FROM COONEY!!! and use MCC tree.) -- currently just using tree 1 here.
tree <- drop.tip(tree, tree$tip.label[which(tree$tip.label %notin% mydata$Species.1)]) # initial name matching.
mydata <- mydata[which(mydata$Species.1 %in% tree$tip.label),]
mydata <- mydata[match(tree$tip.label, mydata$Species.1),]
sum(mydata$Species.1 != tree$tip.label) # sorted (but still specify form below for safety)
[1] 0
Save freame for CB
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
save(mydata, file = "ele_data_for_CB.rdata")
write.csv(mydata, file = "ele_data_for_CB.csv")
Neighbors for sptial analysis.
distm <- mydata[,c("lon", "lat")]
distm <- geodist(distm, measure = "geodesic")
rownames(distm) <- rownames(mydata)
colnames(distm) <- rownames(mydata)
basecols <- ncol(mydata)
# neightbors
coords<-cbind(mydata$lon, mydata$lat); coords<-as.matrix(coords) ; row.names(coords)<-rownames(mydata)
k1 <- knn2nb(knearneigh(coords, longlat = T))
knearneigh: identical points found
nb<- dnearneigh(coords,row.names = row.names(coords), d1=0,d2=max(unlist(nbdists(k1, coords, longlat = T))),longlat=T)
plots for transformations
for (i in c("cost", "lat", "lon","tas_breadth","tas_position","pcp_breadth","pcp_position", "mtn_mass", "dispersal_ability", "pair_age", "distance", "boundary_length", "MAT_overlap")) {
hist(mydata[, i], breaks = 50, main = i)
}













world plots
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
pdf(file="variable_maps.pdf", width = 10, height = 7)
for (i in c("cost", "lat", "lon","tas_breadth","tas_position","pcp_breadth","pcp_position", "mtn_mass", "water_buffering", "dispersal_ability", "pair_age", "distance", "boundary_length", "MAT_overlap", "realm", "landgap")) {
if(i %in% c("cost")){
myc <- mydata[, i]; myc <- vlog(myc)
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[, i], decreasing = F),], aes(y=lat, x=lon, color = myc), alpha = 0.85) +
ggtitle(paste0("ln ",i))+
scale_color_viridis()
print(x)
} else if (i %in% c("realm", "landgap")){
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[, "cost"], decreasing = F),], aes(y=lat, x=lon, color = get(i)), alpha = 0.85) +
ggtitle(paste0(i))+
scale_color_viridis(discrete = T)
print(x)
} else {
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[, "cost"], decreasing = F),], aes(y=lat, x=lon, color = get(i)), alpha = 0.85) +
ggtitle(i)+
scale_color_viridis()
print(x)
}
}
dev.off()
null device
1
# vector 1 added ---
m <- gls(scale(I(vlog(cost))) ~ scale(I(vlog(tas_breadth))) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
Model: scale(I(vlog(cost))) ~ scale(I(vlog(tas_breadth))) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30
Data: mydata
Correlation Structure: corPagel
Formula: ~Species.1
Parameter estimate(s):
lambda
0.1132853
Coefficients:
Correlation:
(Intr) s(I((_ V22 V23 V24 V25 V26 V27 V28 V29
scale(I(vlog(tas_breadth))) -0.030
V22 0.060 -0.016
V23 -0.033 0.002 -0.008
V24 -0.031 0.016 -0.012 0.005
V25 0.015 0.020 -0.003 -0.014 0.004
V26 0.032 0.007 0.004 -0.015 -0.006 0.006
V27 -0.018 -0.020 0.003 0.003 0.001 -0.010 -0.003
V28 0.068 0.000 0.001 0.000 0.002 0.003 -0.017 0.000
V29 -0.038 0.001 -0.012 0.002 0.017 -0.001 -0.018 0.001 0.000
V30 0.031 0.024 -0.007 -0.013 -0.011 0.013 0.061 -0.015 0.001 -0.014
Standardized residuals:
Min Q1 Med Q3 Max
-3.0866866 -0.5483974 0.1080253 0.6419830 2.6354891
Residual standard error: 0.8999846
Degrees of freedom: 235 total; 224 residual
[,1]
[1,] 0.5013446
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.9215695
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)

for(i in c("V22", "V23", "V24", "V25", "V26", "V27", "V28", "V29", "V30")){
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
scale_color_viridis()+
ggtitle(i)
print(x)
}









Is thermal niche breadth predicted by latitude plus latitude2?
# vector 1 added ---
m <- gls(scale(I(vlog(tas_breadth))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30 + V31 + V32 + V33 + V34 + V35 + V36 + V37, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
Model: scale(I(vlog(tas_breadth))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30 + V31 + V32 + V33 + V34 + V35 + V36 + V37
Data: mydata
Correlation Structure: corPagel
Formula: ~Species.1
Parameter estimate(s):
lambda
0.5675592
Coefficients:
Correlation:
(Intr) scl(l) s(I(^2 V22 V23 V24 V25 V26 V27 V28 V29 V30 V31 V32 V33 V34 V35 V36
scale(lat) 0.045
scale(I(lat^2)) -0.077 0.055
V22 0.011 -0.056 -0.055
V23 0.070 0.021 0.019 0.048
V24 0.053 0.032 -0.058 0.076 0.005
V25 -0.024 0.005 -0.134 0.208 0.006 0.167
V26 -0.072 -0.037 0.034 0.040 -0.044 -0.007 -0.014
V27 -0.007 -0.004 -0.078 0.050 -0.032 -0.022 0.090 0.028
V28 0.028 -0.005 -0.006 -0.069 -0.003 0.037 -0.018 -0.057 -0.047
V29 0.002 0.011 -0.022 -0.006 0.002 -0.052 0.005 0.011 0.048 -0.004
V30 -0.038 -0.018 -0.018 -0.017 -0.009 -0.013 -0.005 0.030 -0.011 -0.008 -0.002
V31 0.005 -0.030 -0.009 -0.062 -0.030 0.021 -0.006 -0.046 -0.019 0.014 -0.023 -0.004
V32 0.001 -0.005 0.012 0.022 0.004 -0.002 -0.021 0.004 -0.003 -0.002 -0.008 -0.011 -0.037
V33 -0.008 -0.016 -0.070 0.043 -0.012 -0.014 0.026 0.012 0.050 -0.015 0.014 0.003 -0.007 -0.003
V34 -0.021 0.062 0.018 -0.018 0.010 -0.030 -0.030 0.026 0.022 -0.022 0.074 0.012 -0.027 0.010 0.036
V35 -0.005 0.012 -0.007 -0.006 -0.010 -0.013 -0.012 -0.001 -0.007 -0.001 -0.001 0.001 -0.020 0.002 0.003 0.004
V36 -0.045 -0.014 -0.034 0.063 -0.007 -0.005 0.055 0.025 0.041 -0.022 0.021 0.008 -0.073 -0.028 0.013 -0.004 -0.003
V37 0.027 -0.017 -0.021 0.004 0.017 0.013 -0.006 0.010 -0.006 -0.003 -0.015 0.002 0.008 -0.014 -0.005 -0.012 0.001 -0.008
Standardized residuals:
Min Q1 Med Q3 Max
-2.0731629 -0.6096382 -0.1790288 0.2623287 3.2865813
Residual standard error: 0.5443762
Degrees of freedom: 235 total; 216 residual
[,1]
[1,] 0.1123255
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.9484634
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)

for(i in c("V22", "V23", "V24", "V25", "V26", "V27", "V28", "V29", "V30", "V31", "V32", "V33", "V34", "V35", "V36", "V37")){
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
scale_color_viridis()
print(x)
}
















Is cost predicted by latitude plus latitude2?
# vector 1 added ---
m <- gls(scale(I(vlog(cost))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
Model: scale(I(vlog(cost))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25
Data: mydata
Correlation Structure: corPagel
Formula: ~Species.1
Parameter estimate(s):
lambda
0.1048059
Coefficients:
Correlation:
(Intr) scl(l) s(I(^2 V22 V23 V24
scale(lat) 0.001
scale(I(lat^2)) -0.064 0.104
V22 -0.070 -0.017 0.013
V23 -0.041 -0.007 -0.006 0.011
V24 -0.031 0.013 0.018 0.009 0.001
V25 0.032 0.005 -0.013 -0.021 -0.008 -0.004
Standardized residuals:
Min Q1 Med Q3 Max
-3.2135868 -0.5833627 0.1685737 0.6876315 2.6281318
Residual standard error: 0.9181122
Degrees of freedom: 235 total; 228 residual
[,1]
[1,] 0.4518531
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.7738208
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)

for(i in c("V22", "V23", "V24", "V25")){
x <- ggplot(world)+
geom_sf() +
geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
scale_color_viridis()
print(x)
}





Sensitivity Analyses
# 1 Pair age (all v. < 8mya (end of uplift of Andes))
# 2 Distance (all v. < 1500*1000) (1500 / 110 = ~ 22 degrees)
# 3 MAT_overlap (> 0% v. > 75% (more restrictive == more conservative for this measure.))
# 4 landgap (all v. nogap) *ALL GAPS ARE < 110km (two water grid cells marked as land for having >50% land @ 0.5 degree resolution.)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKClByZXBhcmUgdGhlIFdvcmtzcGFjZQpgYGB7cn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yID0gRkFMU0UpICMgcm1kIG9wdGlvbnMKcm0obGlzdCA9IGxzKCkpOyBpbnZpc2libGUoZ2MoKSkgIyBjbGVhbmluZwpgYGAKPGJyPjxicj48YnI+PGJyPjxicj4KCkNvbnRyb2wgQmxvY2sKYGBge3J9IAojIGYsIGYsIDAuMjUgbG9va3MgbmljZS4KYWxsb3dtaWdyYW50cyA8LSBGICMgT1BUSU9OUzogVCwgRiAKYWxsb3dzeW1wYXRyeSA8LSBGICMgT1BUSU9OUzogVCwgRgptaW5vdmVycGVyYyA8LSAwICMgcmVtb3ZlIHBhaXJzIHRoYXQgZG8gbm90IGhhdmUgdGhlcm1hbCBvdmVybGFwIChhbmFnZW5lc2lzKQpjb3N0dmFyIDwtICJlbGUiCmBgYAo8YnI+PGJyPjxicj48YnI+PGJyPgoKUGFja2FnZXMgJiBQcmVmcwpgYGB7cn0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMgdHVybiBvZmYgc2NpZW50aWZpYyBub3RhdGlvbgonJW5vdGluJScgPC0gTmVnYXRlKCclaW4lJykKcmVxdWlyZShnZ3Bsb3QyKSAjIGxvYWQgcGFja2FnZXMKcmVxdWlyZShHR2FsbHkpCnJlcXVpcmUodmlyaWRpcykKcmVxdWlyZShjYXBlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KEVudlN0YXRzKQpsaWJyYXJ5KGZvcmVjYXN0KQpyZXF1aXJlKG5sbWUpCnJlcXVpcmUoZ2VvZGlzdCkKcmVxdWlyZShsZXRzUikKcmVxdWlyZShzcGRlcCkKcmVxdWlyZShzcGF0aWFscmVnKQpyZXF1aXJlKHJuYXR1cmFsZWFydGgpCnJlcXVpcmUocm5hdHVyYWxlYXJ0aGRhdGEpCnJlcXVpcmUocmdlb3MpCnJlcXVpcmUoc2YpCnJlcXVpcmUocmdkYWwpCnJlcXVpcmUocmFzdGVyKQp3b3JsZCA8LSBuZV9jb2FzdGxpbmUoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQp2bG9nIDwtIGZ1bmN0aW9uKHgpewogICBsb2coIHggKyBhYnMobWluKCB4ICwgbmEucm0gPSBUKSkgKyAxKQp9CgpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKZXhjbHVzaW9uIDwtIHJlYWQuY3N2KGZpbGUgPSAiZXhjbHVzaW9uX25vbnNpbXBhdHJpY19ub25taWdyYW50LmNzdiIpCmV4Y2x1c2lvbiRyZWFsbTFyZWRbaXMubmEoZXhjbHVzaW9uJHJlYWxtMXJlZCldIDwtICJOQSIgIyBOQSBpcyBub3J0aCBhbWVyaWNhIG5vdCBSJ3MgTkEgdmFsdWUuIGZpeC4KZXhjbHVzaW9uJHJlYWxtMmdyZWVuW2lzLm5hKGV4Y2x1c2lvbiRyZWFsbTJncmVlbildIDwtICJOQSIKYGBgCjxicj48YnI+PGJyPjxicj48YnI+CgpMb2FkIE1haW4gRGF0YQpgYGB7cn0KIyBtYWluIGRhdGFmcmFtZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kc2V0d2QoIn4vQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9Qcm9jZXNzX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKbG9hZChmaWxlID0gICJQYWlyX0JhcnJpZXJfRGF0YV9GRUIyMDIxLnJkYXRhIikKbXlkYXRhIDwtIG15cGFpcmRhdGE7IHJtKG15cGFpcmRhdGEpCnJvd25hbWVzKG15ZGF0YSkgPC0gbXlkYXRhJFNwZWNpZXMuMQpteWRhdGFob2xkIDwtIG15ZGF0YQpgYGAKPGJyPjxicj48YnI+PGJyPjxicj4KCmluaXRpYWwgbWFza3MKYGBge3J9CiMgbWlncmF0aW9uIC0tLQppZihhbGxvd21pZ3JhbnRzID09IEYpewogIG15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhJE1pZ3JhdGlvbiA9PSAxLjApLF0KfQoKIyBwYXRyeQppZihhbGxvd3N5bXBhdHJ5ID09IEYpewogIG15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhWyxwYXN0ZTAoY29zdHZhciwgIl9jMCIpXSA+IDAgKSxdICMgZG9lc250IG1hdHRlciBpZiB5b3UgdXNlIGVsZSwgbWF0LCB2YXJ0IHBhdGhzIGhlcmUsIHdpbGwgYmUgc2FtZSBhbnN3ZXIKfQpgYGAKCnNvcnQKYGBge3J9Cm15ZGF0YSR1bmlxdWVQYWlySWQgPT0gZXhjbHVzaW9uJG15ZGF0YS51bmlxdWVQYWlySWQKeCA8LSBteWRhdGFbd2hpY2gobXlkYXRhJFNwZWNpZXMuMSA9PSAiQXB0ZXJ5eF9vd2VuaWkiKSxdCm15ZGF0YSA8LSBteWRhdGFbb3JkZXIobWF0Y2gobXlkYXRhJHVuaXF1ZVBhaXJJZCxleGNsdXNpb24kbXlkYXRhLnVuaXF1ZVBhaXJJZCkpLCBdCnkgPC0gbXlkYXRhW3doaWNoKG15ZGF0YSRTcGVjaWVzLjEgPT0gIkFwdGVyeXhfb3dlbmlpIiksXQojIHN1bSh5IT14LCBuYS5ybSA9IFQpICMgY2hlY2tzLgojIGhlYWQobXlkYXRhKQpteWRhdGEkdW5pcXVlUGFpcklkID09IGV4Y2x1c2lvbiRteWRhdGEudW5pcXVlUGFpcklkCnJtKHgseSkKYGBgCgoKCmBgYHtyfQojICMgQmFzaWMgcmFuZ2UgbWFwcyBmb3IgYWxsIHBhaXJzIChubyBwYXRocykKIyB3ZFBBTSA8LSAiL1VzZXJzL2JvdGVyb2xhYjEvQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9QUkVQL1BBTS9EYXRhIgojIHNldHdkKHdkUEFNKTsgbG9hZCgiY2JQQU0ucmRhdGEiKQojIHNldHdkKCJ+L0JveCBTeW5jL0NCX1ZGX1NoYXJlZC9EcnlfTGFiL1Byb2plY3RzL0pNUEgvUHJvY2Vzc19DbHVzdGVyX091dHB1dHMvRGF0YSIpCiMgcGRmKCJwYWlybWFwczIucGRmIiwgd2lkdGggPSAxOSwgaGVpZ2h0ID0gOS4yNSkKIyBmb3IgKGkgaW4gMTpucm93KG15ZGF0YSkpewojIHggPC0gY2JQQU1bLGMoIkxvbmdpdHVkZSh4KSIsIkxhdGl0dWRlKHkpIixteWRhdGEkU3BlY2llcy4xYmxbaV0pXQojIHggPC0gYXMuZGF0YS5mcmFtZSh4W3hbLDNdID09IDEsXSkKIyBpZihuY29sKHgpID09IDEpIHsKIyAgIHggPC0gdCh4KQojICAgY29sbmFtZXMoeCkgPC0gYygibG9uIiwgImxhdCIsICJwcmVzIikKIyAgIHggPC0gYXMuZGF0YS5mcmFtZSh4KQojIH0gZWxzZSB7CiMgICBjb2xuYW1lcyh4KSA8LSBjKCJsb24iLCAibGF0IiwgInByZXMiKQojIH0KIyAKIyB5IDwtIGNiUEFNWyxjKCJMb25naXR1ZGUoeCkiLCJMYXRpdHVkZSh5KSIsbXlkYXRhJFNwZWNpZXMuMmJsW2ldKV0KIyB5IDwtIGFzLmRhdGEuZnJhbWUoeVt5WywzXSA9PSAxLF0pCiMgaWYobmNvbCh5KSA9PSAxKSB7CiMgICB5IDwtIHQoeSkKIyAgIGNvbG5hbWVzKHkpIDwtIGMoImxvbiIsICJsYXQiLCAicHJlcyIpCiMgICB5IDwtIGFzLmRhdGEuZnJhbWUoeSkKIyAKIyB9IGVsc2UgewojICAgY29sbmFtZXMoeSkgPC0gYygibG9uIiwgImxhdCIsICJwcmVzIikKIyB9CiMgeiA8LSBnZ3Bsb3Qod29ybGQpKwojICAgICBnZW9tX3NmKCkgKwojICAgICBnZW9tX3BvaW50KGRhdGEgPSB4LCBhZXMoeT1sYXQsIHg9bG9uKSwgY29sb3IgPSAicmVkIikgKwojICAgICBnZW9tX3BvaW50KGRhdGEgPSB5LCBhZXMoeT1sYXQsIHg9bG9uKSwgY29sb3IgPSAiZ3JlZW4iKSArCiMgICAgIHRoZW1lX2J3KCkgKwojICAgICBnZ3RpdGxlKGkpCiMgcHJpbnQoeikKIyB9CiMgcHJpbnQoaSkKIyBkZXYub2ZmKCkKYGBgCgpgYGB7cn0KbXlkYXRhX2V4Y2x1c2lvbiA8LSBjYmluZChteWRhdGEsIGV4Y2x1c2lvbikKc2F2ZShteWRhdGFfZXhjbHVzaW9uLCBmaWxlID0gIm15ZGF0YV9leGNsdXNpb24ucmRhdGEiKQpteWRhdGEkcmVhbG0xIDwtIGV4Y2x1c2lvbiRyZWFsbTFyZWQKbXlkYXRhJHJlYWxtMiA8LSBleGNsdXNpb24kcmVhbG0yZ3JlZW4KbXlkYXRhJHJlYWxtIDwtIHBhc3RlMChteWRhdGEkcmVhbG0xLCBteWRhdGEkcmVhbG0yKQp0YWJsZShteWRhdGEkcmVhbG0pCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIkFBSU0iXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiSU1BQSJdIDwtICAiQUFJTSIKbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiQVRJTSJdOyBteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJJTUFUIl0gPC0gICJBVElNIgpteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJBVFBBIl07IG15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIlBBQVQiXSA8LSAgIkFUUEEiCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIklNTlQiXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTlRJTSJdIDwtICAiSU1OVCIKbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTlRBQSJdOyBteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJBQU5UIl0gPC0gICJOVEFBIgpteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJOVE5BIl07IG15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIk5BTlQiXSA8LSAgIk5UTkEiCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIlBBTkEiXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTkFQQSJdIDwtICAiUEFOQSIKbXlkYXRhJHJlYWxtIDwtIGFzLmZhY3RvcihteWRhdGEkcmVhbG0pOyBteWRhdGEkcmVhbG0gPC0gcmVsZXZlbChteWRhdGEkcmVhbG0sICJOVE5UIikKCm15ZGF0YSRsYW5kZ2FwIDwtIGFzLmxvZ2ljYWwoZXhjbHVzaW9uJGlzbGFuZCkKCm15ZGF0YSRjb3Ntb3BvbGl0YW4gPC0gYXMubG9naWNhbChleGNsdXNpb24kY29zbW9wb2xpdGFuKQoKbXlkYXRhJG5ldy5vbGQgPC0gYXMubG9naWNhbChleGNsdXNpb24kbmV3Lm9sZCkKCnJtKGV4Y2x1c2lvbiwgbXlkYXRhX2V4Y2x1c2lvbikKYGBgCgoKCkltcG9zZSBtYXNrcyAmIGRvIGNhbGN1YXRpb25zCmBgYHtyfQojIGZpbHRlciBjb3Ntb3BvbGl0YW4gYW5kIG5ldy9vbGQgd29ybGQgc3BlY2llcyAodGhlcmUgYXJlIHJlbGF0aXZlbHkgZmV3IGFmdGVyIGltcG9zaW5nIHByZXZpb3VzIG1hc2tzLikKbXlkYXRhIDwtIG15ZGF0YVt3aGljaChteWRhdGEkY29zbW9wb2xpdGFuID09IEZBTFNFICYgbXlkYXRhJG5ldy5vbGQgPT0gRkFMU0UpLF0KCiMgZGVwZW5kZW50IHZhcmlhYmxlOiBlbGV2YXRpb25hbCBiYXJyaWVyIHNpemUgLS0tCm15ZGF0YSRjb3N0IDwtIG15ZGF0YVssIHBhc3RlMChjb3N0dmFyLCAiX2MyNSIpXSAKCiMgZGF0YSBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyAgdGhlcm1hbCBvdmVybGFwIC0tLQpteWRhdGEkTUFUX292ZXJsYXAgPC0gbXlkYXRhWyxwYXN0ZTAoIk1BVCIsICJfb3ZfcGVyY19zbXJuZ2UiKV0KbXlkYXRhIDwtIG15ZGF0YVtteWRhdGEkTUFUX292ZXJsYXAgPiBtaW5vdmVycGVyYyxdCgojIHVwZGF0ZSBzb3J0IG9yZGVyIC0tLS0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSRzb3J0b3JkZXIgPC0gc2VxKDE6bnJvdyhteWRhdGEpKQoKIyBsb25naXR1ZGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkbG9uIDwtIG15ZGF0YVsscGFzdGUwKCJsb25fbWVhbl9wYWlyXyIsIGNvc3R2YXIsICJfYzI1IildCgojIGxhdGl0dWRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbXlkYXRhJGxhdCA8LSBteWRhdGFbLHBhc3RlMCgibGF0X21lYW5fcGFpcl8iLCBjb3N0dmFyLCAiX2MyNSIpXQoKIyB0ZW1wZXJhdHVyZSBicmVhZHRoIC0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSR0YXNfYnJlYWR0aCA8LSBteWRhdGEkdGFzX3JhbmdlICMgbWVhbihtZWFuKHNwMSBhbm51YWwgdGFzIHJhbmdlIC0tIG9uZSB2YWx1ZSBwZXIgY2VsbCksIG1lYW4oc3AyIGFubnVhbCB0YXMgcmFuZ2UgLS0gb25lIHZhbHVlIHBlciBjZWxsKSkKCiMgbWVhbiBhbm51YWwgdGVtcGVyYXR1cmUgLS0tLS0tLS0tLS0tLS0KbXlkYXRhJHRhc19wb3NpdGlvbiA8LSBteWRhdGEkdGFzX21lYW4gIyBtZWFuKG1lYW4oc3AxIGFubnVhbCB0YXMgbWVhbiAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHRhcyBtZWFuICAtLSBvbmUgdmFsdWUgcGVyIGNlbGwpKQoKIyBwcmVjaXBpdGF0aW9uIGJyZWFkdGggLS0tLS0tLS0tLS0tLS0tIApteWRhdGEkcGNwX2JyZWFkdGggPC0gbXlkYXRhJHBjcF9yYW5nZSAjIG1lYW4obWVhbihzcDEgYW5udWFsIHBjcCByYW5nZSAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHBjcCByYW5nZSAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSkKCiMgcHJlY2lwaXRhdGlvbiBicmVhZHRoIC0tLS0tLS0tLS0tLS0tLSAKbXlkYXRhJHBjcF9wb3NpdGlvbiA8LSBteWRhdGEkcGNwX21lYW4gIyBtZWFuKG1lYW4oc3AxIGFubnVhbCBwY3AgbWVhbiAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHBjcCBtZWFuICAtLSBvbmUgdmFsdWUgcGVyIGNlbGwpKQoKIyBkaXN0YW5jZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkZGlzdGFuY2UgPC0gbXlkYXRhWyxwYXN0ZTAoImNlbnRyb2lkX2Rpc3RhbmNlXyIsY29zdHZhciwiX2MyNSIpXQoKIyBtb3VudGFpbiBtYXNzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptdG5zIDwtIHJlYWRPR1IoZHNuPSJ+L0JveCBTeW5jL0NCX1ZGX1NoYXJlZC9EcnlfTGFiL1Byb2plY3RzL0pNUEgvT3RoZXJfSW5wdXRfRGF0YS9HTUJBIiwgbGF5ZXI9IkdNQkEgTW91bnRhaW4gSW52ZW50b3J5X3YxLjItV29ybGQiLCB2ZXJib3NlID0gRkFMU0UpCndkUEFNIDwtICIvVXNlcnMvYm90ZXJvbGFiMS9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL1BSRVAvUEFNL0RhdGEiCnNldHdkKHdkUEFNKTsgbG9hZCgiTG9uTGF0X0JpcmRQQU1fcmFzdGVyLnJkYXRhIikKbXRucyA8LSByYXN0ZXJpemUobXRucywgTG9uTGF0X0JpcmRQQU1fcmFzdGVyKQptdG5zQGRhdGFAdmFsdWVzWyFpcy5uYShtdG5zQGRhdGFAdmFsdWVzKV0gPC0gMSAjIHJlcGxhY2UgbW91bnRhaW4gSURzIHdpdGggc2ltcGxlIGNvZGluZy4gMSBmb3IgbW91bnRhaW4uLi4KbXRuc0BkYXRhQHZhbHVlc1tpcy5uYShtdG5zQGRhdGFAdmFsdWVzKV0gPC0gMCAjIC4uLjAgZm9yIG5vIG1vdW50YWluCgpteWRhdGEkbXRuX21hc3MgPC0gTkEKZm9yIChpIGluIDE6bnJvdyhteWRhdGEpKSB7CiAgY29vcmRzMTwtZGF0YS5mcmFtZShsb249bXlkYXRhJGxvbltpXSwgbGF0PW15ZGF0YSRsYXRbaV0pOyBjb29yZGluYXRlcyhjb29yZHMxKTwtYygibG9uIiwibGF0Iik7IGNycyhjb29yZHMxKTwtY3JzKExvbkxhdF9CaXJkUEFNX3Jhc3RlcikgIyBnZXQgY29vcmRpbmF0ZXMKICB6IDwtIGV4dHJhY3QobXRucywgY29vcmRzMSwgYnVmZmVyID0gcmFzdGVyOjpwb2ludERpc3RhbmNlKGMoMCwwKSwgYygwLDgpLCBsb25sYXQgPSBUKSkKICBteWRhdGEkbXRuX21hc3NbaV0gPC0gc3VtKHpbWzFdXSkgLyBsZW5ndGgoeltbMV1dKQp9CgpyYXN0ZXI6OnBvaW50RGlzdGFuY2UoYygwLDApLCBjKDAsOCksIGxvbmxhdCA9IFQpICMgY29ycmVzcG9uZHMgdG8gYSByYWRpdXMgb2YganVzdCBhYm91dCA4IGRlZ3JlZXMuCnJhc3Rlcjo6cG9pbnREaXN0YW5jZShjKDc1LDc1KSwgYyg3NSwoNzUrOCkpLCBsb25sYXQgPSBUKSAjIHBvbGFyIGNpcmNsZXMgYXJlIGJpZ2dlciwgYnV0IG5vdCB0aGF0IG11Y2ggYmlnZ2VyLiBzbyBzaG91bGQgYmUgT0suCnJhc3Rlcjo6cGxvdChtdG5zKQpyYXN0ZXI6OnBsb3Qod29ybGQkZ2VvbWV0cnksIGFkZCA9IFQpCnBsb3RyaXg6OmRyYXcuY2lyY2xlKDcwLCA0MCwgOCwgbnYgPSAxMDAwLCBib3JkZXIgPSAiaG90cGluayIsIGx0eSA9IDEsIGx3ZCA9IDEpCnBsb3RyaXg6OmRyYXcuY2lyY2xlKDE0MCwgLTUsIDgsIG52ID0gMTAwMCwgYm9yZGVyID0gImhvdHBpbmsiLCBsdHkgPSAxLCBsd2QgPSAxKQpwbG90cml4OjpkcmF3LmNpcmNsZSgtODAsIDEwLCA4LCBudiA9IDEwMDAsIGJvcmRlciA9ICJob3RwaW5rIiwgbHR5ID0gMSwgbHdkID0gMSkKcGxvdHJpeDo6ZHJhdy5jaXJjbGUoLTcwLCAtNTAsIDgsIG52ID0gMTAwMCwgYm9yZGVyID0gImhvdHBpbmsiLGx0eSA9IDEsIGx3ZCA9IDEpCgp4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgIm10bl9tYXNzIl0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG10bl9tYXNzKSwgYWxwaGEgPSAwLjkpICsKICBnZ3RpdGxlKGkpK3NjYWxlX2NvbG9yX3ZpcmlkaXMoKQpwcmludCh4KQoKIyB3YXRlciBidWZmZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp3dHIgPC0gcmVhZF9zZigifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL090aGVyX0lucHV0X0RhdGEvbmVfNTBtX29jZWFuL25lXzUwbV9vY2Vhbi5zaHAiKQp0ZW1wIDwtIG10bnMKdmFsdWVzKHRlbXApIDwtIDEwMAp0ZW1wIDwtIG1hc2sodGVtcCwgd3RyKQp3dHIgPC0gbXRucwp2YWx1ZXMod3RyKSA8LSAwCnd0clt0ZW1wID09IDEwMF0gPC0gMTsgcm0odGVtcCkKcGxvdCh3dHIpCgpteWRhdGEkd3RyY2VsbHMgPC0gTkEKbXlkYXRhJHd0cm1hc3MgPC0gTkEKZm9yIChpIGluIDE6bnJvdyhteWRhdGEpKSB7CiAgY29vcmRzMTwtZGF0YS5mcmFtZShsb249bXlkYXRhJGxvbltpXSwgbGF0PW15ZGF0YSRsYXRbaV0pOyBjb29yZGluYXRlcyhjb29yZHMxKTwtYygibG9uIiwibGF0Iik7IGNycyhjb29yZHMxKTwtY3JzKExvbkxhdF9CaXJkUEFNX3Jhc3RlcikgIyBnZXQgY29vcmRpbmF0ZXMKICB6IDwtIGV4dHJhY3Qod3RyLCBjb29yZHMxLCBidWZmZXIgPSByYXN0ZXI6OnBvaW50RGlzdGFuY2UoYygwLDApLCBjKDAsOCksIGxvbmxhdCA9IFQpKQogIG15ZGF0YSRtaW5pcGxvdFtpXSA8LSBsZW5ndGgoeltbMV1dKQogIG15ZGF0YSR3dHJjZWxsc1tpXSA8LSBzdW0oeltbMV1dKQogIG15ZGF0YSR3dHJtYXNzW2ldIDwtIHN1bSh6W1sxXV0pIC8gbGVuZ3RoKHpbWzFdXSkKfQpteWRhdGEkd2F0ZXJfYnVmZmVyaW5nIDwtIG15ZGF0YSR3dHJtYXNzCgp4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgIndhdGVyX2J1ZmZlcmluZyJdLCBkZWNyZWFzaW5nID0gRiksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSB3YXRlcl9idWZmZXJpbmcpLCBhbHBoYSA9IDAuOSkgKwogIGdndGl0bGUoaSkrc2NhbGVfY29sb3JfdmlyaWRpcygpCnByaW50KHgpCgoKIyBkaXNwZXJzYWwgYWJpbGl0eSAtLS0tLS0tLS0tLS0tLS0tLS0tLQpkaXNwYWIgPC0gcmVhZC5jc3YoIn4vQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9PdGhlcl9JbnB1dF9EYXRhL0JpcmQgSGFuZC1XaW5nIEluZGV4L0RhdGFzZXQgSFdJIDIwMjAtMDQtMTAuY3N2IikKbXlkYXRhJGRpc3BlcnNhbF9hYmlsaXR5IDwtIE5BCmZvciAoaSBpbiAxOm5yb3cobXlkYXRhKSl7CiAgZGlzcGFiX3NwMSA8LSBkaXNwYWIkSFdJW2Rpc3BhYiRJVUNOLm5hbWUgPT0gbXlkYXRhJFNwZWNpZXMuMWJsW2ldXQogIGRpc3BhYl9zcDIgPC0gZGlzcGFiJEhXSVtkaXNwYWIkSVVDTi5uYW1lID09IG15ZGF0YSRTcGVjaWVzLjJibFtpXV0KICBkaXNwYWJfcGFpciA8LSBtZWFuKGMoZGlzcGFiX3NwMSwgZGlzcGFiX3NwMiksIG5hLnJtID0gVCkKICBteWRhdGEkZGlzcGVyc2FsX2FiaWxpdHlbaV0gPC0gZGlzcGFiX3BhaXIKICBybShkaXNwYWJfc3AxLCBkaXNwYWJfc3AyLCBkaXNwYWJfcGFpcikKfQpteWRhdGEgPC0gbXlkYXRhWyFpcy5uYW4obXlkYXRhJGRpc3BlcnNhbF9hYmlsaXR5KSxdCgojIHBhaXIgYWdlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSRwYWlyX2FnZSA8LSBteWRhdGEkUGFpci5hZ2UuLk1ZLgoKIyBsZW5ndGggb2YgYm91bmRhcnkgLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkYm91bmRhcnlfbGVuZ3RoIDwtIG15ZGF0YSRib3VuZGFyeV9sZW5ndGhfZWxlX2MyNQoKIyByZXRhaW4gY29scyBvZiBpbnRlcmVzdCBvbmx5LgpteWRhdGEgPC0gbXlkYXRhWyxjKCJ1bmlxdWVQYWlySWQiLCAiU3BlY2llcy4xIiwgIlNwZWNpZXMuMiIsICJTcGVjaWVzLjFibCIsICJTcGVjaWVzLjJibCIsICJjb3N0IiwgImxhdCIsICJsb24iLAogICAgICAgICAgICAgICAgICAgICJ0YXNfYnJlYWR0aCIsInRhc19wb3NpdGlvbiIsICJwY3BfYnJlYWR0aCIsInBjcF9wb3NpdGlvbiIsICJtdG5fbWFzcyIsICJ3YXRlcl9idWZmZXJpbmciLCAKICAgICAgICAgICAgICAgICAgICAiZGlzcGVyc2FsX2FiaWxpdHkiLCAicGFpcl9hZ2UiLCAiZGlzdGFuY2UiLCAiYm91bmRhcnlfbGVuZ3RoIiwgIk1BVF9vdmVybGFwIiwgInJlYWxtIiwKICAgICAgICAgICAgICAgICAgICAibGFuZGdhcCIpXQpgYGAKCmxvYWQgcGh5bG8gYW5kIHBydW5lCmBgYHtyfQojIHBoeWxvIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL090aGVyX0lucHV0X0RhdGEvQmlyZFRyZWVzIikKbG9hZChmaWxlID0gIkJpcmRUcmVlcy5SZGF0YSIpCnRyZWUgPC0gdHJlZXNbWzFdXTsgcm0odHJlZXMpICMgcGljayB0cmVlIChWRiBHRVQgVFJFRVMgRlJPTSBDT09ORVkhISEgYW5kIHVzZSBNQ0MgdHJlZS4pIC0tIGN1cnJlbnRseSBqdXN0IHVzaW5nIHRyZWUgMSBoZXJlLiAKdHJlZSA8LSBkcm9wLnRpcCh0cmVlLCB0cmVlJHRpcC5sYWJlbFt3aGljaCh0cmVlJHRpcC5sYWJlbCAlbm90aW4lIG15ZGF0YSRTcGVjaWVzLjEpXSkgIyBpbml0aWFsIG5hbWUgbWF0Y2hpbmcuCm15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhJFNwZWNpZXMuMSAlaW4lIHRyZWUkdGlwLmxhYmVsKSxdCm15ZGF0YSA8LSBteWRhdGFbbWF0Y2godHJlZSR0aXAubGFiZWwsIG15ZGF0YSRTcGVjaWVzLjEpLF0Kc3VtKG15ZGF0YSRTcGVjaWVzLjEgIT0gdHJlZSR0aXAubGFiZWwpICMgc29ydGVkIChidXQgc3RpbGwgc3BlY2lmeSBmb3JtIGJlbG93IGZvciBzYWZldHkpCmBgYAoKU2F2ZSBmcmVhbWUgZm9yIENCCmBgYHtyfQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKc2F2ZShteWRhdGEsIGZpbGUgPSAiZWxlX2RhdGFfZm9yX0NCLnJkYXRhIikKd3JpdGUuY3N2KG15ZGF0YSwgZmlsZSA9ICJlbGVfZGF0YV9mb3JfQ0IuY3N2IikKYGBgCgoKCk5laWdoYm9ycyBmb3Igc3B0aWFsIGFuYWx5c2lzLiAKYGBge3J9CmRpc3RtIDwtIG15ZGF0YVssYygibG9uIiwgImxhdCIpXQpkaXN0bSA8LSBnZW9kaXN0KGRpc3RtLCBtZWFzdXJlID0gImdlb2Rlc2ljIikKcm93bmFtZXMoZGlzdG0pIDwtIHJvd25hbWVzKG15ZGF0YSkKY29sbmFtZXMoZGlzdG0pIDwtIHJvd25hbWVzKG15ZGF0YSkKYmFzZWNvbHMgPC0gbmNvbChteWRhdGEpCgojIG5laWdodGJvcnMKY29vcmRzPC1jYmluZChteWRhdGEkbG9uLCBteWRhdGEkbGF0KTsgY29vcmRzPC1hcy5tYXRyaXgoY29vcmRzKSA7IHJvdy5uYW1lcyhjb29yZHMpPC1yb3duYW1lcyhteWRhdGEpCmsxIDwtIGtubjJuYihrbmVhcm5laWdoKGNvb3JkcywgbG9uZ2xhdCA9IFQpKQpuYjwtIGRuZWFybmVpZ2goY29vcmRzLHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhjb29yZHMpLCBkMT0wLGQyPW1heCh1bmxpc3QobmJkaXN0cyhrMSwgY29vcmRzLCBsb25nbGF0ID0gVCkpKSxsb25nbGF0PVQpCmBgYAoKCnBsb3RzIGZvciB0cmFuc2Zvcm1hdGlvbnMKYGBge3J9CmZvciAoaSBpbiBjKCJjb3N0IiwgImxhdCIsICJsb24iLCJ0YXNfYnJlYWR0aCIsInRhc19wb3NpdGlvbiIsInBjcF9icmVhZHRoIiwicGNwX3Bvc2l0aW9uIiwgIm10bl9tYXNzIiwgImRpc3BlcnNhbF9hYmlsaXR5IiwgInBhaXJfYWdlIiwgImRpc3RhbmNlIiwgImJvdW5kYXJ5X2xlbmd0aCIsICJNQVRfb3ZlcmxhcCIpKSB7Cmhpc3QobXlkYXRhWywgaV0sIGJyZWFrcyA9IDUwLCBtYWluID0gaSkKfQpgYGAKCndvcmxkIHBsb3RzCmBgYHtyfQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKIyBwZGYoZmlsZT0idmFyaWFibGVfbWFwcy5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA3KQpmb3IgKGkgaW4gYygiY29zdCIsICJsYXQiLCAibG9uIiwidGFzX2JyZWFkdGgiLCJ0YXNfcG9zaXRpb24iLCJwY3BfYnJlYWR0aCIsInBjcF9wb3NpdGlvbiIsICJtdG5fbWFzcyIsICAid2F0ZXJfYnVmZmVyaW5nIiwgImRpc3BlcnNhbF9hYmlsaXR5IiwgInBhaXJfYWdlIiwgImRpc3RhbmNlIiwgImJvdW5kYXJ5X2xlbmd0aCIsICJNQVRfb3ZlcmxhcCIsICJyZWFsbSIsICJsYW5kZ2FwIikpIHsKICBpZihpICVpbiUgYygiY29zdCIpKXsKICAgIG15YyA8LSBteWRhdGFbLCBpXTsgbXljIDwtIHZsb2cobXljKQogICAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogICAgICBnZW9tX3NmKCkgKwogICAgICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgaV0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG15YyksIGFscGhhID0gMC44NSkgKwogICAgICBnZ3RpdGxlKHBhc3RlMCgibG4gIixpKSkrCiAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKQogICAgcHJpbnQoeCkKICB9IGVsc2UgaWYgKGkgJWluJSBjKCJyZWFsbSIsICJsYW5kZ2FwIikpewogICAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogICAgICBnZW9tX3NmKCkgKyAKICAgICAgZ2VvbV9wb2ludChkYXRhID0gbXlkYXRhW29yZGVyKG15ZGF0YVssICJjb3N0Il0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IGdldChpKSksIGFscGhhID0gMC44NSkgKwogICAgICBnZ3RpdGxlKHBhc3RlMChpKSkrCiAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUKQogICAgcHJpbnQoeCkgCiAgfSBlbHNlIHsKICAgIHggPC0gZ2dwbG90KHdvcmxkKSsKICAgICAgZ2VvbV9zZigpICsgCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IG15ZGF0YVtvcmRlcihteWRhdGFbLCAiY29zdCJdLCBkZWNyZWFzaW5nID0gRiksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBnZXQoaSkpLCBhbHBoYSA9IDAuODUpICsKICAgICAgZ2d0aXRsZShpKSsKICAgICAgc2NhbGVfY29sb3JfdmlyaWRpcygpCiAgICBwcmludCh4KSAKICB9Cn0KIyBkZXYub2ZmKCkKYGBgCgoKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQojIG5vIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTtzdW1tYXJ5KG0pCnByaW50KHBhc3RlKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIGRhdGEgYW5kIHByZWRpY3Rpb246ICAiLCBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpKSkKaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCiMgcGxvdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KcGxvdChzY2FsZShJKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSksIHBjaCA9IDE2LAogICAgIHhsYWIgPSAidGhlcm1hbCBuaWNoZSBicmVhZHRoIiwgeWxhYiA9IHBhc3RlMCgibG9nICIsIGNvc3R2YXIsICIgY29zdCIgKSwgbWFpbiA9ICJHbG9iYWwgbW9kZWwiKQpteXggPC0gc2VxKG1pbihzY2FsZSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSwgbWF4KHNjYWxlKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXgKbGluZXMoYygwLDApLCBjKC0xMCwxMDApLCBsdHk9MikKbGluZXMobXl4LG15eSxjb2wgPSAncmVkJykKbSA8LSBnbHMoc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBzY2FsZShJKGxvZyh0YXNfYnJlYWR0aCkpKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQpteXggPC0gc2VxKG1pbihzY2FsZSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSwgbWF4KHNjYWxlKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXgKbGluZXMoYygwLDApLCBjKC0xMCwxMDApLCBsdHk9MikKbGluZXMobXl4LG15eSxjb2wgPSAncmVkJywgbHR5PTIpCgoKCgojIHdpdGggc3BhdGlhbCBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoZm9ybXVsYSA9IHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLG5iPW5iLCBzdHlsZT0iVyIsIEV4YWN0RVYgPSBUUlVFKQpteWRhdGFbLGMoKGJhc2Vjb2xzKzEpOihiYXNlY29scysxKyBkaW0oZml0dGVkKHNhcmNvbCkpWzJdLTEpKV08LWZpdHRlZChzYXJjb2wpCmNvbG5hbWVzKG15ZGF0YSkKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpICsgVjIyICsgVjIzICsgVjI0ICsgVjI1ICsgVjI2ICsgVjI3ICsgVjI4ICsgVjI5ICsgVjMwLCBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIik7IHN1bW1hcnkobSk7IGNvcihwcmVkaWN0KG0pLHNjYWxlKEkodmxvZyhteWRhdGEkY29zdCkpKSkKbWF0eCA8LSBhcy5tYXRyaXgobSRyZXNpZHVhbHMpOyByb3duYW1lcyhtYXR4KSA8LSByb3duYW1lcyhteWRhdGEpCnNwYWMgPC0gbGV0cy5jb3JyZWwoeD1tYXR4LCB5PWRpc3RtLCB6PTEyLCBlcXVpZGlzdGFudCA9IFQsIHBsb3QgPSBUKQptb3Jhbi50ZXN0KHJlc2lkdWFscyhtKSwgbmIybGlzdHcobmIpKSRwLnZhbHVlICMgdG9vIG11Y2guCmhpc3QocmVzaWQobSkpCnBsb3QobSwgcmVzaWQoLiwgdHlwZSA9ICJwIikgfiBmaXR0ZWQoLiksIGFibGluZSA9IDApCnBsb3QobSwgc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBmaXR0ZWQoLiksIGFibGluZSA9IGMoMCwxKSkKcXFub3JtKG0pCgpmb3IoaSBpbiBjKCJWMjIiLCAiVjIzIiwgIlYyNCIsICJWMjUiLCAiVjI2IiwgIlYyNyIsICJWMjgiLCAiVjI5IiwgIlYzMCIpKXsKICB4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWyxpXSksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBteWRhdGFbLGldKSwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkrCiAgZ2d0aXRsZShpKQogIHByaW50KHgpCn0KYGBgCgoKSXMgdGhlcm1hbCBuaWNoZSBicmVhZHRoIHByZWRpY3RlZCBieSBsYXRpdHVkZSBwbHVzIGxhdGl0dWRlMj8gCmBgYHtyfQpteWRhdGEgPC0gbXlkYXRhWywgMTpiYXNlY29sc10KbSA8LSBnbHMoc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTsgc3VtbWFyeShtKQpwcmludChwYXN0ZSgiQ29ycmVsYXRpb24gYmV0d2VlbiBkYXRhIGFuZCBwcmVkaWN0aW9uOiAgIiwgY29yKHByZWRpY3QobSksc2NhbGUoSSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSkpKQpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKIyBwbG90IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwbG90KHNjYWxlKG15ZGF0YSRsYXQpLCBzY2FsZShJKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBwY2ggPSAxNiwKICAgICB4bGFiID0gImxhdGl0dWRlIiwgeWxhYiA9ICJ0aGVybWFsIG5pY2hlIGJyZWFkdGgiLCBtYWluID0gIkdsb2JhbCBtb2RlbCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnKQptIDwtIGdscyhzY2FsZShJKHZsb2codGFzX2JyZWFkdGgpKSkgfiBzY2FsZShsYXQpICsgc2NhbGUoSShsYXReMikpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnLCBsdHk9MikKCgoKCgoKIyB3aXRoIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbSA8LSBnbHMoc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoZm9ybXVsYSA9IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsbmI9bmIsIHN0eWxlPSJXIiwgRXhhY3RFViA9IFRSVUUpCm15ZGF0YVssYygoYmFzZWNvbHMrMSk6KGJhc2Vjb2xzKzErIGRpbShmaXR0ZWQoc2FyY29sKSlbMl0tMSkpXTwtZml0dGVkKHNhcmNvbCkKY29sbmFtZXMobXlkYXRhKSAKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSkgKyBWMjIgKyBWMjMgKyBWMjQgKyBWMjUgKyBWMjYgKyBWMjcgKyBWMjggKyBWMjkgKyBWMzAgKyBWMzEgKyBWMzIgKyBWMzMgKyBWMzQgKyBWMzUgKyBWMzYgKyBWMzcsIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSxmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTsgc3VtbWFyeShtKTsgY29yKHByZWRpY3QobSksc2NhbGUoSSh2bG9nKG15ZGF0YSRjb3N0KSkpKQptYXR4IDwtIGFzLm1hdHJpeChtJHJlc2lkdWFscyk7IHJvd25hbWVzKG1hdHgpIDwtIHJvd25hbWVzKG15ZGF0YSkKc3BhYyA8LSBsZXRzLmNvcnJlbCh4PW1hdHgsIHk9ZGlzdG0sIHo9MTIsIGVxdWlkaXN0YW50ID0gVCwgcGxvdCA9IFQpCm1vcmFuLnRlc3QocmVzaWR1YWxzKG0pLCBuYjJsaXN0dyhuYikpJHAudmFsdWUgIyB0b28gbXVjaC4KaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCmZvcihpIGluIGMoIlYyMiIsICJWMjMiLCAiVjI0IiwgIlYyNSIsICJWMjYiLCAiVjI3IiwgIlYyOCIsICJWMjkiLCAiVjMwIiwgIlYzMSIsICJWMzIiLCAiVjMzIiwgIlYzNCIsICJWMzUiLCAiVjM2IiwgIlYzNyIpKXsKICB4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWyxpXSksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBteWRhdGFbLGldKSwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkKICBwcmludCh4KQp9CmBgYAoKSXMgY29zdCAgcHJlZGljdGVkIGJ5IGxhdGl0dWRlIHBsdXMgbGF0aXR1ZGUyPyAKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSwgZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIik7IHN1bW1hcnkobSkKcHJpbnQocGFzdGUoIkNvcnJlbGF0aW9uIGJldHdlZW4gZGF0YSBhbmQgcHJlZGljdGlvbjogICIsIGNvcihwcmVkaWN0KG0pLHNjYWxlKEkodmxvZyhteWRhdGEkY29zdCkpKSkpKQpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKIyBwbG90IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwbG90KHNjYWxlKG15ZGF0YSRsYXQpLCBzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSksIHBjaCA9IDE2LAogICAgIHhsYWIgPSAibGF0aXR1ZGUiLCB5bGFiID0gImNvc3QiLCBtYWluID0gIkdsb2JhbCBtb2RlbCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnKQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIikKbXl4IDwtIHNlcShtaW4oc2NhbGUobXlkYXRhJGxhdCkpLCBtYXgoc2NhbGUobXlkYXRhJGxhdCkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXggKyBteWNvZWZzWzNdKm15eF4yCmxpbmVzKGMoMCwwKSwgYygtMTAsMTAwKSwgbHR5PTIpCmxpbmVzKG15eCxteXksY29sID0gJ3JlZCcsIGx0eT0yKQoKCgoKCgojIHdpdGggc3BhdGlhbCBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSwgZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIikKIyBzcGF0aWFsIGF1dG9jb3JyIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQptYXR4IDwtIGFzLm1hdHJpeChtJHJlc2lkdWFscyk7IHJvd25hbWVzKG1hdHgpIDwtIHJvd25hbWVzKG15ZGF0YSkKc3BhYyA8LSBsZXRzLmNvcnJlbCh4PW1hdHgsIHk9ZGlzdG0sIHo9MTIsIGVxdWlkaXN0YW50ID0gVCwgcGxvdCA9IFQpCm1vcmFuLnRlc3QocmVzaWR1YWxzKG0pLCBuYjJsaXN0dyhuYikpJHAudmFsdWUgIyBubyBldmlkZW5jZSBvZiBzcGF0aWFsIGNvbXBvbmVudC4uIAoKIyBzcGF0aWFsIGZpbHRlcmluZyAtLS0tLS0tLS0tLS0tLS0tLS0tLQpybShzYXJjb2wpCnNhcmNvbCA8LSBTcGF0aWFsRmlsdGVyaW5nKGZvcm11bGEgPSBzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsbmI9bmIsIHN0eWxlPSJXIiwgRXhhY3RFViA9IFRSVUUpCm15ZGF0YVssYygoYmFzZWNvbHMrMSk6KGJhc2Vjb2xzKzErIGRpbShmaXR0ZWQoc2FyY29sKSlbMl0tMSkpXTwtZml0dGVkKHNhcmNvbCkKY29sbmFtZXMobXlkYXRhKSAKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSArIFYyMiArIFYyMyArIFYyNCArIFYyNSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpOyBzdW1tYXJ5KG0pOyBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIHRvbyBtdWNoLgpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKZm9yKGkgaW4gYygiVjIyIiwgIlYyMyIsICJWMjQiLCAiVjI1IikpewogIHggPC0gZ2dwbG90KHdvcmxkKSsKICBnZW9tX3NmKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG15ZGF0YVtvcmRlcihteWRhdGFbLGldKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG15ZGF0YVssaV0pLCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKQogIHByaW50KHgpCn0KYGBgCgoKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkoKHRhc19icmVhZHRoKSkpICsgc2NhbGUoSSgodGFzX3Bvc2l0aW9uKSkpICsgc2NhbGUoSSgocGNwX2JyZWFkdGgpKSkgKyBzY2FsZShJKChwY3BfcG9zaXRpb24pKSkgKyAKICAgICAgICAgICBzY2FsZShJKChtdG5fbWFzcykpKSArIHNjYWxlKEkoKHdhdGVyX2J1ZmZlcmluZykpKSArIHNjYWxlKEkoKGRpc3BlcnNhbF9hYmlsaXR5KSkpICsgc2NhbGUoSSgocGFpcl9hZ2UpKSkgKyBzY2FsZShJKChkaXN0YW5jZSkpKSArIHNjYWxlKEkoKGJvdW5kYXJ5X2xlbmd0aCkpKSArIAogICAgICAgICAgIHNjYWxlKEkoKE1BVF9vdmVybGFwKSkpICsgbGFuZGdhcCArIHJlYWxtLAogICAgICAgICBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsIGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpO3N1bW1hcnkobSkKIyBjYXI6OnZpZihtKSAjIGRvZXMgbm90IHdvcmsgd2l0aCByZWFsbSBhZGRlZCBpbi4gCnByaW50KHBhc3RlKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIGRhdGEgYW5kIHByZWRpY3Rpb246ICAiLCBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpKSkKaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCgojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBzY2FsZShJKCh0YXNfYnJlYWR0aCkpKSArIHNjYWxlKEkoKHRhc19wb3NpdGlvbikpKSArIHNjYWxlKEkoKHBjcF9icmVhZHRoKSkpICsgc2NhbGUoSSgocGNwX3Bvc2l0aW9uKSkpICsgCiAgICAgICAgICAgc2NhbGUoSSgobXRuX21hc3MpKSkgKyBzY2FsZShJKCh3YXRlcl9idWZmZXJpbmcpKSkgKyBzY2FsZShJKChkaXNwZXJzYWxfYWJpbGl0eSkpKSArIHNjYWxlKEkoKHBhaXJfYWdlKSkpICsgc2NhbGUoSSgoZGlzdGFuY2UpKSkgKyBzY2FsZShJKChib3VuZGFyeV9sZW5ndGgpKSkgKyAKICAgICAgICAgICBzY2FsZShJKChNQVRfb3ZlcmxhcCkpKSArIGxhbmRnYXAgKyByZWFsbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSxuYj1uYiwgc3R5bGU9IlciLCBFeGFjdEVWID0gVFJVRSkKbXlkYXRhWyxjKChiYXNlY29scysxKTooYmFzZWNvbHMrMSsgZGltKGZpdHRlZChzYXJjb2wpKVsyXS0xKSldPC1maXR0ZWQoc2FyY29sKQpjb2xuYW1lcyhteWRhdGEpIAoKIyB2ZWN0b3IgMSBhZGRlZCAtLS0KbXlkYXRhJHJlYWxtMiA8LSBhcy5mYWN0b3IobXlkYXRhJHJlYWxtMik7IG15ZGF0YSRyZWFsbTIgPC0gcmVsZXZlbChteWRhdGEkcmVhbG0yLCByZWYgPSAiTlQiKQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkoKHRhc19icmVhZHRoKSkpICsgc2NhbGUoSSgodGFzX3Bvc2l0aW9uKSkpICsgc2NhbGUoSSgocGNwX2JyZWFkdGgpKSkgKyBzY2FsZShJKChwY3BfcG9zaXRpb24pKSkgKyAKICAgICAgICAgICBzY2FsZShJKChtdG5fbWFzcykpKSArIHNjYWxlKEkoKHdhdGVyX2J1ZmZlcmluZykpKSArIHNjYWxlKEkoKGRpc3BlcnNhbF9hYmlsaXR5KSkpICsgc2NhbGUoSSgocGFpcl9hZ2UpKSkgKyBzY2FsZShJKChkaXN0YW5jZSkpKSArIHNjYWxlKEkoKGJvdW5kYXJ5X2xlbmd0aCkpKSArIAogICAgICAgICAgIHNjYWxlKEkoKE1BVF9vdmVybGFwKSkpICsgbGFuZGdhcCArIHJlYWxtICsgVjIyICsgVjIzICsgVjI0ICsgVjI1ICsgVjI2ICsgVjI3ICsgVjI4ICsgVjI5ICsgVjMwICsgVjMxICsgVjMyICsgVjMzLCBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsIGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpOyBzdW1tYXJ5KG0pOyBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIHRvbyBtdWNoLgpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKCmZvcihpIGluIGMoIlYyMiIsIlYyMyIsICJWMjQiLCAiVjI1IiwgIlYyNiIsICJWMjciLCAiVjI4IiwgIlYyOSIsICJWMzAiLCAiVjMxIiwgIlYzMiIsICJWMzMiKSl7CiAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogIGdlb21fc2YoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbXlkYXRhW29yZGVyKG15ZGF0YVssaV0pLF0sIGFlcyh5PWxhdCwgeD1sb24sIGNvbG9yID0gbXlkYXRhWyxpXSksIGFscGhhID0gMC45KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpCiAgcHJpbnQoeCkKfQpgYGAKCgpTZW5zaXRpdml0eSBBbmFseXNlcwpgYGB7cn0KIyAxIFBhaXIgYWdlIChhbGwgdi4gPCA4bXlhIChlbmQgb2YgdXBsaWZ0IG9mIEFuZGVzKSkKIyAyIERpc3RhbmNlIChhbGwgdi4gPCAxNTAwKjEwMDApICgxNTAwIC8gMTEwID0gfiAyMiBkZWdyZWVzKQojIDMgTUFUX292ZXJsYXAgKD4gMCUgdi4gPiA3NSUgKG1vcmUgcmVzdHJpY3RpdmUgPT0gbW9yZSBjb25zZXJ2YXRpdmUgZm9yIHRoaXMgbWVhc3VyZS4pKQojIDQgbGFuZGdhcCAoYWxsIHYuIG5vZ2FwKSAqQUxMIEdBUFMgQVJFIDwgMTEwa20gKHR3byB3YXRlciBncmlkIGNlbGxzIG1hcmtlZCBhcyBsYW5kIGZvciBoYXZpbmcgPjUwJSBsYW5kIEAgMC41IGRlZ3JlZSByZXNvbHV0aW9uLikKYGBg